package com.jiangyg.mall.core.utils.bean;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 类描述：bean的属性工具类
 * 
 * @author jiangyg
 * @date 2020-07-14
 * @version 2.0
 */
public class PropertyUtils {

    /**
     * bean的字段缓存
     */
    private static final Map<Class<?>, Map<String, Field>> cacheBeanFields = new ConcurrentHashMap<>(64);

    /**
     * 功能描述：获取bean的所有字段Map集合
     * 
     * @param clazz bean
     * @return 返回bean的Map集合
     */
    public static Map<String, Field> getFieldsMap(Class<?> clazz) {
        // 优先从缓存中获取bean的字段
        Map<String, Field> fieldMap = cacheBeanFields.get(clazz);
        if (fieldMap == null) {
            fieldMap = initLoadBeanFieldsCache(clazz);
        }
        return fieldMap;
    }

    /**
     * 功能描述：获取bean的所有字段数组
     * 
     * @param clazz bean
     * @return 返回Field[]
     */
    public static Field[] getFields(Class<?> clazz) {
        return getFieldsMap(clazz).values().toArray(new Field[0]);
    }

    /**
     * 功能描述：获取bean的指定字段
     * 
     * @param clazz bean
     * @param name  指定字段名
     * @return 返回Field
     */
    public static Field getField(Class<?> clazz, String name) {
        return getFieldsMap(clazz).get(name);
    }

    /**
     * 功能描述：初始化加载并获取bean字段缓存
     * 
     * @param clazz bean
     * @return 返回Field[]
     */
    private static synchronized Map<String, Field> initLoadBeanFieldsCache(Class<?> clazz) {
        Map<String, Field> fieldMap = cacheBeanFields.get(clazz);
        if (fieldMap == null) {
            fieldMap = new HashMap<>(32);
            // 获取bean的所有属性列表
            for (Class<?> targetClass = clazz; targetClass != Object.class; targetClass = targetClass.getSuperclass()) {
                Field[] fields = targetClass.getDeclaredFields();
                for (Field field : fields) {
                    String fieldName = field.getName();
                    // 排除序列化字段
                    if (StringUtils.equals(fieldName, "serialVersionUID")) {
                        continue;
                    }
                    fieldMap.put(fieldName, field);
                }
            }
            cacheBeanFields.put(clazz, fieldMap);
        }
        return fieldMap;
    }

    /**
     * 功能描述：获取JavaBean的PropertyDescriptor数组
     * 
     * @param bean JavaBean
     * @return 返回PropertyDescriptor数组
     */
    public static PropertyDescriptor[] getPropertyDescriptors(Object bean) {
        BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(bean);
        return beanWrapper.getPropertyDescriptors();
    }

    /**
     * 功能描述：获取JavaBean的PropertyDescriptor数组
     * 
     * @param clazz JavaBean的class
     * @return 返回PropertyDescriptor数组
     */
    public static PropertyDescriptor[] getPropertyDescriptors(Class<?> clazz) {
        return org.springframework.beans.BeanUtils.getPropertyDescriptors(clazz);
    }

    /**
     * 功能描述：获取JavaBean的PropertyDescriptor
     * 
     * @param bean         JavaBean
     * @param propertyName 属性名
     * @return PropertyDescriptor
     */
    public static PropertyDescriptor getPropertyDescriptor(Object bean, String propertyName) {
        BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(bean);
        return beanWrapper.getPropertyDescriptor(propertyName);
    }

    /**
     * 功能描述：获取JavaBean的PropertyDescriptor
     * 
     * @param clazz        JavaBean的class
     * @param propertyName 属性名
     * @return PropertyDescriptor
     */
    public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz, String propertyName) {
        return org.springframework.beans.BeanUtils.getPropertyDescriptor(clazz, propertyName);
    }

}
